using ASPApiDemo.Common.Option;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using System.Reflection;

namespace ASPApiDemo.Common.Core;

// 应用程序核心类，提供全局访问服务、配置和环境的静态方法
public class AppService
{
    // 静态构造函数，初始化有效类型集合
    // 在类首次被访问时由CLR自动调用且仅执行一次，不能有参数和修饰符
    static AppService()
    {
        // 从所有程序集中获取所有类型
        EffectiveTypes = Assemblies.SelectMany(GetTypes);
    }

    // 私有字段，标记应用是否正在运行
    private static bool _isRun;
    // 标记应用是否已构建
    public static bool IsBuild { get; set; }
    // 标记应用是否正在运行，设置时同时设置IsBuild属性
    public static bool IsRun
    {
        get => _isRun;
        set => _isRun = IsBuild = value;
    }
    // 获取应用程序所有有效的程序集，排除系统程序集(Microsoft...)和Nuget包
    public static readonly IEnumerable<Assembly> Assemblies = RuntimeExtension.GetAllAssemblies();
    // 存储所有有效程序集中的类型
    public static readonly IEnumerable<Type> EffectiveTypes;
    // 获取根服务提供器，只有在应用运行或已构建时才可用，优先使用App.GetService()手动获取服务
    public static IServiceProvider RootServices => IsRun || IsBuild ? InternalApp.RootServices : null;
    // 提供对Web主机环境的访问，用于确定当前环境（开发、生产等）
    public static IWebHostEnvironment WebHostEnvironment => InternalApp.WebHostEnvironment;
    // 提供对泛型主机环境的访问
    public static IHostEnvironment HostEnvironment => InternalApp.HostEnvironment;
    // 提供对应用程序配置的访问
    public static IConfiguration Configuration => InternalApp.Configuration;
    // 获取当前HTTP请求的上下文，通过IHttpContextAccessor服务
    public static HttpContext HttpContext => RootServices?.GetService<IHttpContextAccessor>()?.HttpContext;
    //public static IUser User => GetService<IUser>();

    #region Service

    // 根据服务类型获取适当的服务提供者容器
    public static IServiceProvider GetServiceProvider(Type serviceType, bool mustBuild = false,
        bool throwException = true)
    {
        // 如果主机环境为空，或者根服务不为空且请求的服务是单例服务，则返回根服务提供器
        if (HostEnvironment == null || RootServices != null &&
            InternalApp.InternalServices
                .Where(u =>
                    u.ServiceType ==
                    (serviceType.IsGenericType ? serviceType.GetGenericTypeDefinition() : serviceType))
                .Any(u => u.Lifetime == ServiceLifetime.Singleton))
            return RootServices;
        // 获取请求生存周期的服务
        // 如果当前有HTTP请求上下文，则使用请求的服务提供器
        if (HttpContext?.RequestServices != null)
            return HttpContext.RequestServices;

        // 如果根服务提供器可用，创建一个新的服务范围
        if (RootServices != null)
        {
            IServiceScope scope = RootServices.CreateScope();
            return scope.ServiceProvider;
        }

        // 如果必须在应用构建后才能获取服务
        if (mustBuild)
        {
            // 如果允许抛出异常，则抛出应用程序异常
            if (throwException)
            {
                throw new ApplicationException("当前不可用，必须要等到 WebApplication Build后");
            }

            return default;
        }

        // 从内部服务集合构建一个新的服务提供器
        ServiceProvider serviceProvider = InternalApp.InternalServices.BuildServiceProvider();
        return serviceProvider;
    }
    // 获取指定类型的服务实例
    public static T GetService<T>(bool mustBuild = true) where T : class
    {
        return GetService(typeof(T), null, mustBuild) as T;
    }
    // 从指定的服务提供器获取服务，如果未提供服务提供器则自动解析
    public static T GetService<T>(IServiceProvider serviceProvider, bool mustBuild = true) where T : class
    {
        serviceProvider ??= GetServiceProvider(typeof(T), mustBuild, false);
        return serviceProvider?.GetService<T>();
    }

    // 根据类型获取服务实例，支持指定服务提供器
    public static object GetService(Type type, IServiceProvider serviceProvider = null, bool mustBuild = true)
    {
        serviceProvider ??= GetServiceProvider(type, mustBuild, false);
        return serviceProvider?.GetService(type);
    }

    #endregion

    #region private

    // 从指定程序集中获取所有公共类型
    private static IEnumerable<Type> GetTypes(Assembly ass)
    {
        // 初始化一个空的类型数组
        Type[] source = Array.Empty<Type>();
        try
        {
            // 尝试获取程序集中的所有类型
            source = ass.GetTypes();
        }
        catch
        {
            // 如果加载失败，输出错误信息
            Console.WriteLine($@"Error load `{ass.FullName}` assembly.");
        }

        // 只返回公共类型
        return source.Where(u => u.IsPublic);
    }

    #endregion

    #region Options

    // 从配置中获取指定类型的配置选项
    public static TOptions GetConfig<TOptions>()
        where TOptions : class, IConfigurableOptions
    {
        // 从配置中获取指定路径的配置节，并绑定到强类型对象
        TOptions instance = Configuration
            .GetSection(ConfigurableOptions.GetConfigurationPath(typeof(TOptions)))
            .Get<TOptions>();
        return instance;
    }
    // 获取IOptions<T>服务中的选项值
    public static TOptions GetOptions<TOptions>(IServiceProvider serviceProvider = null) where TOptions : class, new()
    {
        // 从服务提供器获取IOptions<T>服务
        IOptions<TOptions> service = GetService<IOptions<TOptions>>(serviceProvider ?? RootServices, false);
        return service?.Value;
    }
    // 获取IOptionsMonitor<T>服务中的当前选项值，支持运行时更新
    public static TOptions GetOptionsMonitor<TOptions>(IServiceProvider serviceProvider = null)
        where TOptions : class, new()
    {
        // 从服务提供器获取IOptionsMonitor<T>服务
        IOptionsMonitor<TOptions> service =
            GetService<IOptionsMonitor<TOptions>>(serviceProvider ?? RootServices, false);
        return service?.CurrentValue;
    }
    // 获取IOptionsSnapshot<T>服务中的选项值，每个请求范围内创建一次
    public static TOptions GetOptionsSnapshot<TOptions>(IServiceProvider serviceProvider = null)
        where TOptions : class, new()
    {
        // 从服务提供器获取IOptionsSnapshot<T>服务
        IOptionsSnapshot<TOptions> service = GetService<IOptionsSnapshot<TOptions>>(serviceProvider, false);
        return service?.Value;
    }

    #endregion
}